﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using JDKill.Definitions.QRCode;
using JDKill.Definitions.Product;
using JDKill.Definitions.Address;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using JDKill.Definitions.User;
using HtmlAgilityPack;
using System.Text.RegularExpressions;
using JDKill.Definitions.Cart;

namespace JDKill.Services
{
    public class JDService:AbstractService
    {
        private HttpCookie _cookie = null;
        private Encoding _respEncoding = null;

        public JDService()
        {
            _cookie = new HttpCookie();
            _respEncoding = Encoding.GetEncoding("gb2312");
            base.SetUserAgent("Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36");
            base.SetRequestEncoding(_respEncoding);
        }

        public void SetCookie(string cookie)
        {
            _cookie.Clear();
            _cookie.SetCookie(cookie);
        }

        public string GetCookie()
        {
            return _cookie.ToString();
        }

        public string GetProductId(string productUrl)
        {
            try
            {
                int index1 = productUrl.IndexOf(".htm");
                int index2 = productUrl.LastIndexOf("/", index1);
                index2++;
                return productUrl.Substring(index2, index1 - index2);
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        public List<string> QueryProductImages(string productId)
        {
            var url = GetProductDetailUrl(productId);
            var result = Get(url, null, null, _cookie.ToString());
            var html = result.GetHtml(_respEncoding);
            var doc = LoadHtml(html);
            var imgUrl = doc.SelectSingleNode("//img[@id='spec-img']").Attributes["data-origin"].Value;
            if (!imgUrl.StartsWith("http"))
                imgUrl = "https:" + imgUrl;

            return new List<string>() { imgUrl };
        }

        public List<AreaInfo> GetAreaInfoList(string areaId)
        {
            List<AreaInfo> result = new List<AreaInfo>();

            string[] parts = areaId.Split('_');
            List<AreaInfo> list = QuerySubAreaListOfChina();
            for (int i = 0; i < parts.Length - 1; i++)
            {
                string id = parts[i];
                AreaInfo areaInfo = list.Find(m => m.id == id);
                result.Add(areaInfo);
                list = QuerySubAreaList(id);
            }
            return result;
        }

        public string GetAreaId(List<AreaInfo> areaList)
        {
            StringBuilder builder = new StringBuilder();
            foreach (var item in areaList)
            {
                builder.Append(item.id + "_");
            }
            builder.Append("0");
            return builder.ToString();
        }

        public string GetProductDetailUrl(string productId)
        {
            return string.Format("https://item.jd.com/{0}.html", productId);
        }

        public Image GetQRCodeImage()
        {
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("appid", 133));
            paras.Add(new KeyValuePair<string, object>("size", 147));
            paras.Add(new KeyValuePair<string, object>("t", GetUnixTimeInMill()));
            HttpResult result = Get("https://qr.m.jd.com/show",
                "https://passport.jd.com/uc/login?ltype=logout", paras, _cookie.ToString());
            _cookie.SetCookie(result.Cookie);
            return result.GetImage();
        }

        public QRCodeResult CheckQRCode()
        {
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("callback", GetJQueryHeader()));
            paras.Add(new KeyValuePair<string, object>("appid", 133));
            paras.Add(new KeyValuePair<string, object>("token", _cookie.GetCookie("wlfstk_smdl")));
            paras.Add(new KeyValuePair<string, object>("_", GetUnixTimeInMill()));
            HttpResult result = Get("https://qr.m.jd.com/check",
                "https://passport.jd.com/new/login.aspx", paras, _cookie.ToString());
            _cookie.SetCookie(result.Cookie);
            string html = result.GetHtml();
            string json = FixJson(html);
            QRCodeResult obj = JsonConvert.DeserializeObject<QRCodeResult>(json);
            /*
             * jQuery2708921({
                   "code" : 201,
                   "msg" : "二维码未扫描 ，请扫描二维码"
                })
             * 
             * jQuery1315410({
                   "code" : 202,
                   "msg" : "请手机客户端确认登录"
                })
             * 
             * jQuery4528580({
                   "code" : 200,
                   "ticket" : "AAEAIBtdMMCwGA_D-iZ5QvpZbBo613os6g79tv_AIEEhx5e3"
                })
             */
            return obj;
        }

        public QRCodeValidationResult ValidateQRCodeTicket(string ticket)
        {
            /*
             * https://passport.jd.com/uc/qrCodeTicketValidation?t=AAEAIBtdMMCwGA_D-iZ5QvpZbBo600os3g79tv_AIEEhx5q3
             */
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("t", ticket));
            HttpResult result = Get("https://passport.jd.com/uc/qrCodeTicketValidation",
                "https://passport.jd.com/uc/login?ltype=logout", paras, _cookie.ToString());
            _cookie.SetCookie(result.Cookie);
            string html = result.GetHtml(_respEncoding);
            QRCodeValidationResult obj = JsonConvert.DeserializeObject<QRCodeValidationResult>(html);
            /*
             * {"returnCode":0,"url":"https://www.jd.com/?cu=true&utm_source=baidu-search&utm_medium=cpc&utm_campaign=t_262767352_baidusearch&utm_term=27669656277_0_ba78d2c4b70f4b15bd870215f1fddfcc"}
             */
            return obj;
        }

        public UserInfoDetail QueryUserInfoDetail()
        {
            UserInfoDetail info = new UserInfoDetail();

            // https://i.jd.com/user/info
            HttpResult result = Get("https://i.jd.com/user/info", null, null, _cookie.ToString());
            string html = result.GetHtml();
            if (!html.Contains("userVo.nickName"))
            {
                throw new Exception("未登陆");
            }
            var doc = LoadHtml(html);
            info.NickName = doc.SelectSingleNode("//input[@name='userVo.nickName']").Attributes["value"].Value;
            var nodes = doc.SelectNodes("//strong");
            info.UserName = nodes[0].InnerText.Trim();
            info.LoginName = nodes[1].InnerText.Trim();
            info.Email = nodes[2].InnerText.Trim();
            return info;
        }

        public UserInfoBrief QueryUserInfoBrief()
        {
            UserInfoBrief info = null;

            // https://passport.jd.com/user/petName/getUserInfoForMiniJd.action?callback=jQuery2331509&_=1519287144751 
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("callback", GetJQueryHeader()));
            paras.Add(new KeyValuePair<string, object>("_", GetUnixTimeInMill()));
            HttpResult result = Get(
                "https://passport.jd.com/user/petName/getUserInfoForMiniJd.action", 
                "https://i.jd.com/user/userinfo/showImg.html", null, _cookie.ToString());
            string html = result.GetHtml(_respEncoding);
            string json = FixJson(html);
            info = JsonConvert.DeserializeObject<UserInfoBrief>(json);
            info.Avatar = "https:" + info.Avatar;

            return info;
        }

        public List<AddressDetail> QueryAddressList()
        {
            // https://cd.jd.com/usual/address?callback=jQuery9245592&_=1519283987401
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string,object>("callback", GetJQueryHeader()));
            paras.Add(new KeyValuePair<string,object>("_", GetUnixTimeInMill()));
            HttpResult result = Get("https://cd.jd.com/usual/address",
                "https://item.jd.com/23777530072.html", paras, _cookie.ToString());
            string html = result.GetHtml(_respEncoding);
            string json = FixJson(html);
            return JsonConvert.DeserializeObject<List<AddressDetail>>(json);
        }

        public List<ProductDetail> QueryProductDetailList(ProductCategory category, string locationId)
        {
            List<ProductDetail> productList = new List<ProductDetail>();

            var productIdList = new List<string>();
            if (category == ProductCategory.Custom)
            {
                productIdList = GlobalContext.CustomProducts;
            }
            for (int i = 0; i < productIdList.Count; i++)
            {
                productList.Add(QueryProductDetail(productIdList[i], locationId, true));
            }

            return productList;
        }

        public void ReserveProduct(ProductDetail product)
        {
            // 获取商品预约地址
            string url = "https://yushou.jd.com/youshouinfo.action";
            string refer = GetProductDetailUrl(product.Id);
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("callback", "fetchJSON"));
            paras.Add(new KeyValuePair<string, object>("sku", product.Id));
            var result = Get(url, refer, paras, _cookie.ToString());
            var html = result.GetHtml(_respEncoding);
            var json = FixJson(html);
            if (!json.Contains("url"))
            {
                throw new Exception("不需要预约");
            }
            JObject obj = JsonConvert.DeserializeObject(json) as JObject;
            string reserveUrl = obj["url"].ToString();
            reserveUrl = FixUrlToHttps(reserveUrl);

            // 预约商品
            result = Get(reserveUrl, refer, null, _cookie.ToString());
            html = result.GetHtml();
            // 您已成功预约过了，无需重复预约
            // 预约成功，已获得抢购资格
            if (!html.Contains("无需重复预约") && !html.Contains("预约成功"))
            {
                throw new Exception("预约失败");
            }
        }

        public ProductDetail QueryProductDetail(string productId, string locationId,bool queryPrice)
        {
            ProductDetail info = new ProductDetail();

            string productUrl = string.Format("https://item.jd.com/{0}.html", productId);
            HttpResult result = Get(productUrl, "https://passport.jd.com/uc/login?ltype=logout", null, _cookie.ToString());
            string html = result.GetHtml(_respEncoding);
            var doc = LoadHtml(html);
            // <div class="sku-name">斐讯K2P月光银 AC1200智能双频全千兆无线路由器 有线无线双千兆 WiFi穿墙</div>
            string skuName = doc.SelectSingleNode("//div[@class='sku-name']").InnerText.Trim();
            string cartLink = string.Empty;
            if (html.Contains("InitCartUrl"))
            {
                cartLink = doc.SelectSingleNode("//a[@id='InitCartUrl']").Attributes["href"].Value;
                cartLink = FixUrlToHttps(cartLink);
            }
            else
            {
                // https://cart.jd.com/gate.action?pid=4255683&pcount=1&ptype=1
                cartLink = string.Format("https://cart.jd.com/gate.action?pid={0}&pcount=1&ptype=1", productId);
            }
            info.Id = productId;
            info.CartUrl = cartLink;
            info.Name = skuName;
            if (queryPrice)
            {
                info.Price = QueryProductPrice(productId);
            }
            info.KillPrice = -1;
            QueryProductStatus(productId, locationId, out info.State, out info.LeftCount);
            return info;
        }

        private double QueryProductPrice(string productId)
        {
            string url = "https://p.3.cn/prices/mgets";
            string referer = string.Format("https://item.jd.com/{0}.html", productId);
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("type", 1));
            paras.Add(new KeyValuePair<string, object>("pduid", GetUnixTimeInMill()));
            paras.Add(new KeyValuePair<string, object>("skuIds", "J_" + productId));
            paras.Add(new KeyValuePair<string, object>("callback", GetJQueryHeader()));
            HttpResult result = Get(url, referer, paras, null);
            /*
             * jQuery899809([{"op":"1999.00","m":"2009.00","id":"J_5428209","p":"1999.00"}]);
             */
            string html = result.GetHtml(_respEncoding);
            string json = FixJson(html);
            if (json.Contains("error"))
            {
                var obj = JsonConvert.DeserializeObject(json) as JObject;
                var error = obj["error"].ToString();
                Console.WriteLine(json);
                throw new Exception("查询价格错误：" + error);
            }
            JArray arr = JsonConvert.DeserializeObject(json) as JArray;
            return Convert.ToDouble(arr[0]["p"].ToString());
        }

        public void QueryProductStatus(string productId, string locationId,
            out ProductState productState,
            out string leftCount)
        {
            string url = "https://c0.3.cn/stocks";
            string referer = string.Format("https://item.jd.com/{0}.html", productId);
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("type", "getstocks"));
            paras.Add(new KeyValuePair<string, object>("area", locationId));
            paras.Add(new KeyValuePair<string, object>("skuIds", productId));
            paras.Add(new KeyValuePair<string, object>("callback", GetJQueryHeader()));
            paras.Add(new KeyValuePair<string, object>("_", GetUnixTimeInMill()));
            HttpResult result = Get(url, referer, paras, null);
            string html = result.GetHtml(_respEncoding);
            string json = FixJson(html);
            // {"3820581":{"StockState":33,"freshEdi":null,"ac":"-1","ad":"-1","skuState":1,"ae":"-1","PopType":0,"af":"-1","sidDely":"65","channel":1,"StockStateName":"现货","rid":null,"rfg":0,"ArrivalDate":"","IsPurchase":true,"rn":-1}}
            JObject obj = JsonConvert.DeserializeObject(json) as JObject;

            productState = (ProductState)Convert.ToInt32(obj[productId]["StockState"].ToString());
            leftCount = obj[productId]["StockStateName"].ToString();
        }

        public List<CartProductInfo> QueryCartProductList()
        {
            // step2:查看购物车详情
            List<CartProductInfo> cartProductInfoList = new List<CartProductInfo>();
            var result = Get("https://cart.jd.com/cart.action", null, null, _cookie.ToString());
            var html = result.GetHtml(Encoding.UTF8);
            var doc = LoadHtml(html);
            var itemNodes = doc.SelectNodes("//div[@class='item-form']");
            foreach (var itemNode in itemNodes)
            {
                var node = itemNode.SelectSingleNode(
                    "div[@class='cell p-checkbox']/div[@class='cart-checkbox']/input");
                var checkedValue = "unchecked";
                if (node.Attributes.Contains("checked"))
                {
                    checkedValue = node.Attributes["checked"].Value;
                }
                var values = node.Attributes["value"].Value.Split('_');

                node = itemNode.SelectSingleNode(
                    "div[@class='cell p-goods']/div[@class='goods-item']/div[@class='p-img']/a");
                var href = node.Attributes["href"].Value;
                var index1 = href.LastIndexOf(".");
                var index2 = href.LastIndexOf("/", index1) + 1;
                var productId = href.Substring(index2, index1 - index2);
                node = node.SelectSingleNode("img");
                var name = node.Attributes["alt"].Value;

                // 普通用户价格
                node = itemNode.SelectSingleNode(
                    "div[@class='cell p-price p-price-new ']/strong");
                var price = "";
                if (node != null)
                {
                    price = node.InnerText;
                }
                else
                {
                    // plus会员价格
                    node = itemNode.SelectSingleNode(
                       "div[@class='cell p-price p-price-new  project-plus-price']/strong");
                    price = node.InnerText;
                }
                price = price.Replace("¥", "");

                node = itemNode.SelectSingleNode(
                    "div[@class='cell p-sum']/strong");
                var priceSum = node.InnerText.Replace("¥", "");

                node = itemNode.SelectSingleNode(
                   "div[@class='cell p-quantity']/div[@class='quantity-form']/input");
                var count = node.Attributes["value"].Value;

                CartProductInfo cartProductInfo = new CartProductInfo();
                cartProductInfo.ProductType = values[1];
                cartProductInfo.PromoId = "0";
                if (values.Length == 3)
                {
                    cartProductInfo.PromoId = values[2];
                }
                cartProductInfo.Checked = checkedValue.ToLower() == "checked";
                cartProductInfo.ProductId = productId;
                cartProductInfo.ProductName = name;
                cartProductInfo.Count = Convert.ToInt32(count);
                cartProductInfo.Price = Convert.ToDouble(price);
                cartProductInfo.PriceSum = Convert.ToDouble(priceSum);
                cartProductInfoList.Add(cartProductInfo);
            }

            return cartProductInfoList;
        }

        public void RemoveCartProduct(string productId)
        {
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("callback", GetJQueryHeader()));
            paras.Add(new KeyValuePair<string, object>("method", "RemoveProduct"));
            paras.Add(new KeyValuePair<string, object>("cartId", productId));
            paras.Add(new KeyValuePair<string, object>("_", GetUnixTimeInMill()));
            var result = Get("https://cart.jd.com/cart/miniCartServiceNew.action", "https://cart.jd.com/cart.action", paras, _cookie.ToString());
            var html = result.GetHtml(Encoding.UTF8);
            if (!html.Contains("true"))
            {
                throw new Exception("移除失败");
            }
        }

        public void ChangeCartProductSelection(CartProductInfo product, string locationId, bool selected)
        {
            var paras = CreateParas();
            if (selected)
            {
                /*
                 * outSkus:
                    pid:3820581
                    ptype:13
                    packId:0
                    targetId:213665896
                    promoID:213665896
                    locationId:5-164-47712
                    t:0
                 */
                paras.Add(new KeyValuePair<string, object>("outSkus", ""));
                paras.Add(new KeyValuePair<string, object>("pid", product.ProductId));
                paras.Add(new KeyValuePair<string, object>("ptype", product.ProductType));
                paras.Add(new KeyValuePair<string, object>("packId", "0"));
                paras.Add(new KeyValuePair<string, object>("targetId", product.PromoId));
                paras.Add(new KeyValuePair<string, object>("promoID", product.PromoId));
                paras.Add(new KeyValuePair<string, object>("locationId", locationId));
                paras.Add(new KeyValuePair<string, object>("t", 0));
                var result = Post("https://cart.jd.com/selectItem.action", "https://cart.jd.com/cart.action", paras, _cookie.ToString());
                var html = result.GetHtml(Encoding.UTF8);
            }
            else
            {
                /*
                 * outSkus:
                    pid:3820581
                    ptype:13
                    packId:0
                    targetId:213665896
                    promoID:213665896
                    locationId:5-164-47712
                    t:0
                 */
                paras.Add(new KeyValuePair<string, object>("outSkus", ""));
                paras.Add(new KeyValuePair<string, object>("pid", product.ProductId));
                paras.Add(new KeyValuePair<string, object>("ptype", product.ProductType));
                paras.Add(new KeyValuePair<string, object>("packId", "0"));
                paras.Add(new KeyValuePair<string, object>("targetId", product.PromoId));
                paras.Add(new KeyValuePair<string, object>("promoID", product.PromoId));
                paras.Add(new KeyValuePair<string, object>("locationId", locationId));
                paras.Add(new KeyValuePair<string, object>("t", 0));
                var result = Post("https://cart.jd.com/cancelItem.action", "https://cart.jd.com/cart.action", paras, _cookie.ToString());
                var html = result.GetHtml(Encoding.UTF8);
            }
        }

        public void ChangeCartProductNum(CartProductInfo product, int count, string locationId)
        {
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("t", 0));
            paras.Add(new KeyValuePair<string, object>("venderId", "8888"));
            paras.Add(new KeyValuePair<string, object>("pid", product.ProductId));
            paras.Add(new KeyValuePair<string, object>("pcount", count));
            paras.Add(new KeyValuePair<string, object>("ptype", product.ProductType));
            paras.Add(new KeyValuePair<string, object>("targetId", product.PromoId));
            paras.Add(new KeyValuePair<string, object>("promoID", product.PromoId));
            paras.Add(new KeyValuePair<string, object>("outSkus", ""));
            paras.Add(new KeyValuePair<string, object>("random", new Random().NextDouble()));
            paras.Add(new KeyValuePair<string, object>("locationId", locationId));
            var result = Post("https://cart.jd.com/changeNum.action", "https://cart.jd.com/cart.action", paras, _cookie.ToString());
            var html = result.GetHtml(Encoding.UTF8);
        }

        public void ChangeOrderReceiver(AddressDetail address)
        {
            /*
             * consigneeParam.id	138710538
                consigneeParam.type	null
                consigneeParam.commonConsigneeSize	5
                consigneeParam.isUpdateCommonAddress	0
                consigneeParam.giftSenderConsigneeName	
                consigneeParam.giftSendeConsigneeMobile	
                consigneeParam.noteGiftSender	false
                consigneeParam.isSelfPick	0
                consigneeParam.selfPickOptimize	1
                consigneeParam.pickType	0
             */
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("consigneeParam.id", address.Id));
            paras.Add(new KeyValuePair<string, object>("consigneeParam.type", "null"));
            paras.Add(new KeyValuePair<string, object>("consigneeParam.commonConsigneeSize", 5));
            paras.Add(new KeyValuePair<string, object>("consigneeParam.isUpdateCommonAddress", 0));
            paras.Add(new KeyValuePair<string, object>("consigneeParam.giftSenderConsigneeName", ""));
            paras.Add(new KeyValuePair<string, object>("consigneeParam.idgiftSendeConsigneeMobile", ""));
            paras.Add(new KeyValuePair<string, object>("consigneeParam.noteGiftSender", "false"));
            paras.Add(new KeyValuePair<string, object>("consigneeParam.isSelfPick", 0));
            paras.Add(new KeyValuePair<string, object>("consigneeParam.selfPickOptimize", 1));
            paras.Add(new KeyValuePair<string, object>("consigneeParam.pickType", 0));
            var result = Post("https://trade.jd.com/shopping/dynamic/consignee/saveConsignee.action",
                "https://trade.jd.com/shopping/order/getOrderInfo.action", paras, _cookie.ToString());
            var html = result.GetHtml(Encoding.UTF8);
        }

        public void CreateOrder(ProductDetail product, int productCount, AddressDetail address)
        {
            // step1:添加到购物车
            var refer = GetProductDetailUrl(product.Id);
            var result = Get(product.CartUrl, refer, null, _cookie.ToString());
            var html = result.GetHtml(Encoding.UTF8);
            // <h3 class="ftx-02">商品已成功加入购物车！</h3>
            if (!html.Contains("ftx-02"))
            {
                throw new Exception("添加到购物车失败");
            }

            //var paras = CreateParas();
            //paras.Add(new KeyValuePair<string, object>("venderId", "8888"));
            //paras.Add(new KeyValuePair<string, object>("targetId", "0"));
            //paras.Add(new KeyValuePair<string, object>("promoID", "0"));
            //paras.Add(new KeyValuePair<string, object>("outSkus", ""));
            //paras.Add(new KeyValuePair<string, object>("ptype", "1"));
            //paras.Add(new KeyValuePair<string, object>("pid", product.Id));
            //paras.Add(new KeyValuePair<string, object>("pcount", productCount));
            //paras.Add(new KeyValuePair<string, object>("random", new Random().NextDouble()));
            //paras.Add(new KeyValuePair<string, object>("locationId", address.GetLocationId()));
            //var result = Post("http://cart.jd.com/changeNum.action", null, paras, _cookie.ToString());
            //var html = result.GetHtml(Encoding.UTF8);

            // step2:调整下单个数
            List<CartProductInfo> cartProductInfoList = QueryCartProductList();
            CartProductInfo found = cartProductInfoList.Find(m => m.ProductId == product.Id);
            if (found == null)
            {
                throw new Exception("购物车中未找到对应的商品");
            }
            ChangeCartProductNum(found, productCount, address.GetLocationId());

            // step3:调整非下单商品勾选状态
            foreach (var item in cartProductInfoList)
            {
                if (item.ProductId != product.Id && item.Checked)
                {
                    ChangeCartProductSelection(item, address.GetLocationId(), false);
                }
            }

            // step4:调整收货地址
            ChangeOrderReceiver(address);

            // step5:下单
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("overseaPurchaseCookies", ""));
            paras.Add(new KeyValuePair<string, object>("submitOrderParam.fp", ""));
            paras.Add(new KeyValuePair<string, object>("submitOrderParam.eid", ""));
            paras.Add(new KeyValuePair<string, object>("submitOrderParam.btSupport", "1"));
            paras.Add(new KeyValuePair<string, object>("submitOrderParam.sopNotPutInvoice", "false"));
            paras.Add(new KeyValuePair<string, object>("submitOrderParam.ignorePriceChange", "0"));
            paras.Add(new KeyValuePair<string, object>("submitOrderParam.trackID", _cookie.GetCookie("TrackID")));
            result = Post("http://trade.jd.com/shopping/order/submitOrder.action", null, paras, _cookie.ToString());
            html = result.GetHtml(_respEncoding);
            // {"message":null,"sign":null,"pin":"frozleaf","resultCode":0,"success":true,"addressVO":null,"needCheckCode":false,"orderId":72542400943,"submitSkuNum":1,"deductMoneyFlag":0,"goJumpOrderCenter":false,"payInfo":null,"scaleSkuInfoListVO":null,"purchaseSkuInfoListVO":null,"overSea":false,"orderXml":null,"cartXml":null,"noStockSkuIds":"","reqInfo":null}
            JObject obj = JsonConvert.DeserializeObject(html) as JObject;
            string orderId = obj["orderId"].ToString();
            int submitProductNum = Convert.ToInt32(obj["submitSkuNum"].ToString());
        }

        public void AddToCart(string url)
        {
            HttpResult result = Request(HttpMethod.Get, url, null, null, _cookie.ToString());
            string html = result.GetHtml(_respEncoding);
        }

        public List<AreaInfo> QuerySubAreaListOfChina()
        {
            return QuerySubAreaList("4744");
        }

        public List<AreaInfo> QuerySubAreaList(string areaId)
        {
            // https://d.jd.com/area/get?callback=getAreaListCallback&fid=4744
            string url = "https://d.jd.com/area/get";
            string referer = string.Format("https://item.jd.com/{0}.html", "10956260662");
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("callback", "getAreaListCallback"));
            paras.Add(new KeyValuePair<string, object>("fid", areaId));
            HttpResult result = Get(url, referer, paras, null);
            string html = result.GetHtml(_respEncoding);
            string json = FixJson(html);
            return JsonConvert.DeserializeObject<List<AreaInfo>>(json);
        }

        /// <summary>
        /// 根据秒杀分组内的商品id列表
        /// </summary>
        /// <param name="groupId"></param>
        /// <param name="locationId"></param>
        /// <returns></returns>
        public List<ProductDetail> QueryMiaoShaoProductsByGroup(string groupId, string locationId)
        {
            // https://ai.jd.com/index_new?app=Seckill&action=pcMiaoShaAreaList&callback=pcMiaoShaAreaList&gid=-1&_=1525874230652
            List<ProductDetail> list = new List<ProductDetail>();
            string url = "https://ai.jd.com/index_new";
            string referer = "https://miaosha.jd.com/";
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("app", "Seckill"));
            paras.Add(new KeyValuePair<string, object>("action", "pcMiaoShaAreaList"));
            paras.Add(new KeyValuePair<string, object>("callback", "pcMiaoShaAreaList"));
            paras.Add(new KeyValuePair<string, object>("gid", groupId));
            paras.Add(new KeyValuePair<string, object>("_", GetUnixTimeInMill()));
            HttpResult result = Get(url, referer, paras, null);
            string html = result.GetHtml(_respEncoding);
            string json = FixJson(html);
            JObject obj = JsonConvert.DeserializeObject(json) as JObject;
            JArray arr = obj["miaoShaList"] as JArray;
            ProductDetail detail = null;
            for (int i = 0; i < arr.Count; i++)
            {
                JObject g = arr[i] as JObject;
                detail = new ProductDetail();
                detail.Name = g["wname"].ToString();
                detail.Id = g["wareId"].ToString();
                detail.Price = Convert.ToDouble(g["jdPrice"].ToString());
                detail.KillPrice = Convert.ToDouble(g["miaoShaPrice"].ToString());
                QueryProductStatus(detail.Id, locationId, out detail.State, out detail.LeftCount);
                list.Add(detail);
            }

            return list;
        }

        /// <summary>
        /// 查询秒杀分组
        /// </summary>
        /// <returns></returns>
        public Dictionary<string,string> QueryMiaoShaGroup()
        {
            // https://ai.jd.com/index_new?app=Seckill&action=pcMiaoShaAreaList&callback=pcMiaoShaAreaList&gid=-1&_=1525874230652
            Dictionary<string, string> dic = new Dictionary<string, string>();
            string url = "https://ai.jd.com/index_new";
            string referer = "https://miaosha.jd.com/";
            var paras = CreateParas();
            paras.Add(new KeyValuePair<string, object>("app", "Seckill"));
            paras.Add(new KeyValuePair<string, object>("action", "pcMiaoShaAreaList"));
            paras.Add(new KeyValuePair<string, object>("callback", "pcMiaoShaAreaList"));
            paras.Add(new KeyValuePair<string, object>("gid", "-1"));
            paras.Add(new KeyValuePair<string, object>("_", GetUnixTimeInMill()));
            HttpResult result = Get(url, referer, paras, null);
            string html = result.GetHtml(_respEncoding);
            string json = FixJson(html);
            JObject obj = JsonConvert.DeserializeObject(json) as JObject;
            JArray arr = obj["groups"] as JArray;
            for (int i = 0; i < arr.Count; i++)
            {
                JObject g = arr[i] as JObject;
                string gid = g["gid"].ToString();
                string name = g["name"].ToString();
                dic.Add(gid, name);
            }

            return dic;
        }

        private string FixJson(string str)
        {
            int index1 = str.IndexOf("(") + 1;
            int index2 = str.LastIndexOf(")");
            return str.Substring(index1, index2 - index1);
        }

        private string GetJQueryHeader()
        {
            return "jQuery" + new Random().Next(100000, 999999);
        }

        protected HtmlNode LoadHtml(string html)
        {
            HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
            doc.LoadHtml(html);

            return doc.DocumentNode;
        }

        protected Dictionary<string,string> GetNameValues(string html)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();

            MatchCollection matchs = Regex.Matches(html, @"<input.+?(?=name=""(?<name>\S+)"").+?(?=value=""(?<value>\S+)"").+?>");
            if (matchs.Count > 0)
            {
                foreach (Match mitem in matchs)
                {
                    string name = mitem.Groups["name"].ToString();
                    string value = mitem.Groups["value"].ToString();
                    // name:uuid _t
                    if (!dic.ContainsKey(name))
                    {
                        dic.Add(name, value);
                    }
                }
            }
            return dic;
        }

        public Image GetImage(String url)
        {
            var result = Request(HttpMethod.Get, url, null, null, null);
            return result.GetImage();
        }

        private string FixUrlToHttps(string url)
        {
            if (url.StartsWith("//"))
            {
                url = "https:" + url;
            }
            return url;
        }
    }
}
